﻿using AutoMapper;
using Microsoft.IdentityModel.Tokens;
using Minio.DataModel;
using Modules;
using Modules.Corp;
using Modules.Payroll;
using Modules.Person;
using Modules.Project;
using Modules.Project.Entitys;
using Modules.System.Settings.Entitys;
using Modules.System.Settings;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Exceptions;
using System.Text.RegularExpressions;
using static Modules.Payroll.PayrollConstants;
using static Modules.Person.PersonConstants;

namespace ManagementApi.Services.Import
{
    [UseDI(ServiceLifetime.Scoped)]
    public class ImportService
    {
        private readonly IMapper mapper;
        private readonly ProjectService projectService;
        private readonly WagePayrollService payrollService;
        private readonly ProjectGroupService projectGroupService;
        private readonly PersonService personService;
        private readonly PersonBankService personBankService;
        private readonly CorpService corpService;
        private readonly WagePayrollSettingService payrollSettingService;
        private readonly ProjectGroupMemberService projectGroupMemberService;
        private readonly WagePayrollDetailService wagePayrollDetailService;

        public ImportService(IMapper mapper, ProjectService projectService, WagePayrollService payrollService, ProjectGroupService projectGroupService, PersonService personService, PersonBankService personBankService, CorpService corpService, WagePayrollSettingService payrollSettingService, ProjectGroupMemberService projectGroupMemberService, WagePayrollDetailService wagePayrollDetailService)
        {
            this.mapper = mapper;
            this.projectService = projectService;
            this.payrollService = payrollService;
            this.projectGroupService = projectGroupService;
            this.personService = personService;
            this.personBankService = personBankService;
            this.corpService = corpService;
            this.payrollSettingService = payrollSettingService;
            this.projectGroupMemberService = projectGroupMemberService;
            this.wagePayrollDetailService = wagePayrollDetailService;
        }

        /// <summary>
        /// 验证工资卡Excel并且转换成集合
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        /// <exception cref="BusinessException"></exception>
        public IEnumerable<PersonBankImportDto> VerifyPersonBankExcelToList(IFormFile file)
        {
            var data = ImportExcelUtil<PersonBankImportForm>.InputExcel(file, 1);
            if (data == null || data.Count == 0)
                throw new BusinessException("数据格式解析错误，请上传正确的Excel");
            List<PersonBankImportDto> dtos = new();
            mapper.Map(data, dtos);
            foreach (var item in dtos)
            {
                #region 非空验证

                if (string.IsNullOrEmpty(item.IdCard))
                {
                    item.Status = false;
                    item.ErrorMsg += "人员身份证不能为空;</br>";
                    item.ErrorCount += 1;
                }
                if (string.IsNullOrEmpty(item.CardNo))
                {
                    item.Status = false;
                    item.ErrorMsg += "发放工资银行卡号不能为空;</br>";
                    item.ErrorCount += 1;
                }
                //if (!item.Type.HasValue)
                if (string.IsNullOrWhiteSpace(item.TypeName))
                {
                    item.Status = false;
                    item.ErrorMsg += "工资卡类型不能为空;</br>";
                    item.ErrorCount += 1;
                }
                if (!string.IsNullOrWhiteSpace(item.TypeName) && !Enum.IsDefined(typeof(工资卡类型), item.TypeName))
                {
                    item.Status = false;
                    item.ErrorMsg += "工资卡类型只能是:社会保障卡,银行卡;</br>";
                    item.ErrorCount += 1;
                }
                if (string.IsNullOrEmpty(item.BankName))
                {
                    item.Status = false;
                    item.ErrorMsg += "发放工资银行名称不能为空;</br>";
                    item.ErrorCount += 1;
                }

                #endregion 非空验证
            }
            return dtos;
        }

        /// <summary>
        /// 验证工资单Excel并且转换成集合
        /// </summary>
        /// <param name="projectId">项目Id</param>
        /// <param name="file"></param>
        /// <returns></returns>
        /// <exception cref="BusinessException"></exception>
        public IEnumerable<PayrollDetailImportDto> VerifyPayrollExcelToList(int projectId, IFormFile file)
        {
            var data = ImportExcelUtil<PayrollDetailImportForm>.InputExcel(file, 9);
            if (data == null || data.Count == 0)
                throw new BusinessException("数据格式解析错误，请上传正确的Excel");
            ProjectInfo? projectInfo = projectService.GetProjectInfoByName(data.FirstOrDefault()?.ProjectName.Trim() ?? string.Empty);
            if (projectInfo == null)
                throw new BusinessException("项目名称错误");
            if (projectInfo.ProjectId != projectId)
                throw new BusinessException("项目名称不是当前项目，请切换至该项目进行操作");
            List<PayrollDetailImportDto> dtos = new();
            mapper.Map(data, dtos);
            foreach (var item in dtos)
            {
                #region 非空验证

                if (string.IsNullOrEmpty(item.ProjectName))
                {
                    item.Status = false;
                    item.ErrorMsg += "项目名称不能为空;</br>";
                    item.ErrorCount += 1;
                }
                if (string.IsNullOrEmpty(item.GroupName))
                {
                    item.Status = false;
                    item.ErrorMsg += "劳务班组不能为空;</br>";
                    item.ErrorCount += 1;
                }
                if (string.IsNullOrEmpty(item.PersonName))
                {
                    item.Status = false;
                    item.ErrorMsg += "姓名不能为空;</br>";
                    item.ErrorCount += 1;
                }
                if (string.IsNullOrEmpty(item.IdCard))
                {
                    item.Status = false;
                    item.ErrorMsg += "身份证号不能为空;</br>";
                    item.ErrorCount += 1;
                }
                if (string.IsNullOrEmpty(item.BankName))
                {
                    item.Status = false;
                    item.ErrorMsg += "开户行不能为空;</br>";
                    item.ErrorCount += 1;
                }
                if (string.IsNullOrEmpty(item.PersonBankNo))
                {
                    item.Status = false;
                    item.ErrorMsg += "银行卡号不能为空;</br>";
                    item.ErrorCount += 1;
                }

                #endregion 非空验证
            }
            return dtos;
        }

        /// <summary>
        /// 导入时验证工资明细数据是否有效
        /// </summary>
        /// <param name="id"></param>
        /// <param name="forms"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public IEnumerable<WagePayrollDetail> VerifyPayrollDetailsToEntity(int id, IEnumerable<PayrollDetailImportForm> forms)
        {
            List<WagePayrollDetail> wagePayrollDetails = new List<WagePayrollDetail>();
            WagePayroll? wagePayroll = payrollService.Get(id);
            if (wagePayroll == null) throw new BusinessException("工资单信息不存在");
            CorpInfo? corpInfo = corpService.GetCorpInfo(wagePayroll.CorpId);
            if (corpInfo == null) throw new BusinessException("工资单企业信息不存在");
            if (payrollService.Verify(wagePayroll))
            {
                foreach (var item in forms)
                {
                    item.IdCard = item.IdCard.Trim();
                    item.IdCard = item.IdCard.Trim();
                    #region 1.验证项目名称是否合法

                    ProjectInfo? projectInfo = projectService.GetProjectInfoByName(item.ProjectName);
                    if (projectInfo == null) throw new BusinessException($"项目名称{item.ProjectName}错误");
                    if (wagePayroll.ProjectId != projectInfo.ProjectId)
                        throw new BusinessException($"项目名称{item.ProjectName}错误");

                    #endregion 1.验证项目名称是否合法

                    #region 2.验证班组信息是否合法

                    ProjectGroup? projectGroup = projectGroupService.GetProjectGroupByPjCorpName(projectInfo.ProjectId, wagePayroll.CorpId, item.GroupName);
                    if (projectGroup == null) throw new BusinessException($"项目名称{item.ProjectName}下，参建单位为{corpInfo.Name}，没有{item.GroupName} 班组");

                    #endregion 2.验证班组信息是否合法

                    #region 3.验证人员信息是否合法

                    PersonInfo? personInfo = personService.GetPersonByCardNo(item.IdCard);
                    if (personInfo == null) throw new BusinessException($"身份证{item.IdCard} 不在人员信息列表中");
                    if (personInfo.Name != item.PersonName.Trim()) throw new BusinessException($"身份证为{item.IdCard} 的人员姓名不为{item.PersonName}");

                    ProjectGroupMember? projectGroupMember = projectGroupMemberService.GetProjectGroupMemberByGroupPerson(projectGroup.GroupId, personInfo.PersonId);
                    if (projectGroupMember == null) throw new BusinessException($"身份证为{item.IdCard} 的人员不在{projectGroup.Name}");
                    #endregion 3.验证人员信息是否合法

                    #region 4.验证银行卡信息是否存在

                    PersonBank? personBank = personBankService.GetPersonBankByCardNo(item.PersonBankNo);
                    if (personBank == null) throw new BusinessException($"银行卡{item.PersonBankNo} 不存在，请先录入人员{item.PersonName}的银行卡信息");

                    #endregion 4.验证银行卡信息是否存在

                    #region 5.验证当前人员月度限额是否超出设定最大值
                    WageMonthAmountSettings wageMonthAmountSettings = SettingManager<WageMonthAmountSettings>.Instance.Get();

                    IEnumerable<WagePayrollDetail> wagePayrolls = wagePayrollDetailService.GetPayrollDetailsByPersonIdAndMonth(personInfo.PersonId, wagePayroll.Month);
                    if ((wagePayrolls.Sum(a => a.AmountPaid) + item.AmountApplied) > wageMonthAmountSettings.MaxAmount)
                        throw new BusinessException($"人员{personInfo.Name} 当月的工资总额不能超过 {wageMonthAmountSettings.MaxAmount}");
                    #endregion

                    if (wagePayroll.WageType == 工资单类型.正常工资单 && item.AttendanceDays <= 0) throw new BusinessException($"人员{personInfo.Name} 的考勤天数不能为空");
                    WagePayrollDetail detail = new()
                    {
                        ProjectId = projectInfo.ProjectId,
                        PayrollId = id,
                        GroupId = projectGroup.GroupId,
                        MemberId = projectGroupMember.Id,
                        WorkType = projectGroupMember.Type,
                        PersonId = personInfo.PersonId,
                        PersonName = personInfo.Name,
                        IdCard = personInfo.CardNumber,
                        BankCardNo = item.PersonBankNo,
                        BankName = item.BankName,
                        AttendanceDays = item.AttendanceDays,
                        AmountApplied = item.AmountApplied,
                        Status = 工资发放状态.未发,
                        CreateTime = DateTime.Now,
                        Month = wagePayroll.Month
                    };
                    wagePayrollDetails.Add(detail);
                }
            }

            #region 验证工资限额设置

            var allSettings = payrollSettingService.GetAll();
            var wageProject = projectService.GetProjectInfo(wagePayroll.ProjectId) ?? throw new BusinessException("工资单所属项目不存在");
            var effectSettings = allSettings.Where(i => i.IndustryType == wageProject.IndustryType);
            if (effectSettings == null || !effectSettings.Any()) effectSettings = allSettings.Where(i => i.IndustryType == null);
            if (effectSettings == null || !effectSettings.Any()) return wagePayrollDetails;

            var members = projectGroupMemberService.GetProjectGroupMembersByGroupIds(wagePayrollDetails.Select(i => i.GroupId));
            foreach (var item in wagePayrollDetails)
            {
                var member = members.FirstOrDefault(i => i.GroupId == item.GroupId && i.PersonId == item.PersonId && i.ProjectId == item.ProjectId);
                if (member == null) continue;
                var effectSetting = effectSettings.FirstOrDefault(i => i.WorkType == member.Type) ?? effectSettings.FirstOrDefault(i => i.WorkType == null);
                if (effectSetting == null) continue;
                if (!member.Type.HasValue) continue;
                if (effectSetting.MonthlyLimit < item.AmountApplied) throw new BusinessException($"工种为:{member.Type.GetDescription()}的人员每月限制发放工资:{effectSetting.MonthlyLimit}元");
                if (wagePayroll.WageType == 工资单类型.非正常工资单) continue;
                if (effectSetting.DailyLimit < (item.AmountApplied / item.AttendanceDays)) throw new BusinessException($"工种为:{member.Type.GetDescription()}的人员每日限制发放工资:{effectSetting.DailyLimit}元");
            }

            #endregion 验证工资限额设置

            return wagePayrollDetails;
        }
    }
}